import logger from '../utils/logger.js'
/**
 * GOC 错误处理器
 * 提供统一的错误处理、分类和用户友好的错误信息
 */
class GocErrorHandler {
  constructor() {
    this.errorTypes = {
      SYNTAX: 'syntax',
      RUNTIME: 'runtime',
      TIMEOUT: 'timeout',
      MEMORY: 'memory',
      CANVAS: 'canvas'
    }
  }

  /**
   * 处理语法错误
   * @param {Error} error - 原始错误对象
   * @param {string} code - 源代码
   * @param {number} line - 错误行号
   * @param {number} column - 错误列号
   * @returns {Object} 格式化的错误信息
   */
  handleSyntaxError(error, code, line = 0, column = 0) {
    const lines = code.split('\n')
    const errorLine = lines[line] || ''
    
    return {
      type: this.errorTypes.SYNTAX,
      message: this.getSyntaxErrorMessage(error.message),
      originalError: error.message,
      line: line + 1,
      column: column + 1,
      code: errorLine.trim(),
      suggestion: this.getSyntaxSuggestion(error.message, errorLine),
      severity: 'error'
    }
  }

  /**
   * 处理运行时错误
   * @param {Error} error - 原始错误对象
   * @param {string} context - 错误上下文
   * @returns {Object} 格式化的错误信息
   */
  handleRuntimeError(error, context = '') {
    return {
      type: this.errorTypes.RUNTIME,
      message: this.getRuntimeErrorMessage(error.message),
      originalError: error.message,
      context: context,
      suggestion: this.getRuntimeSuggestion(error.message),
      severity: 'error'
    }
  }

  /**
   * 处理超时错误
   * @param {number} timeoutMs - 超时时间（毫秒）
   * @param {string} operation - 超时的操作
   * @returns {Object} 格式化的错误信息
   */
  handleTimeoutError(timeoutMs, operation = '代码执行') {
    return {
      type: this.errorTypes.TIMEOUT,
      message: `${operation}超时（${timeoutMs}ms）`,
      timeout: timeoutMs,
      operation: operation,
      suggestion: '请检查代码中是否有无限循环，或尝试简化代码逻辑',
      severity: 'error'
    }
  }

  /**
   * 处理内存错误
   * @param {Error} error - 原始错误对象
   * @returns {Object} 格式化的错误信息
   */
  handleMemoryError(error) {
    return {
      type: this.errorTypes.MEMORY,
      message: '内存不足，无法继续执行',
      originalError: error.message,
      suggestion: '请减少绘制的复杂度或降低画布分辨率',
      severity: 'error'
    }
  }

  /**
   * 处理画布错误
   * @param {Error} error - 原始错误对象
   * @returns {Object} 格式化的错误信息
   */
  handleCanvasError(error) {
    return {
      type: this.errorTypes.CANVAS,
      message: '画布操作失败',
      originalError: error.message,
      suggestion: '请检查画布是否已正确初始化',
      severity: 'error'
    }
  }

  /**
   * 获取语法错误的用户友好消息
   * @param {string} originalMessage - 原始错误消息
   * @returns {string} 用户友好的错误消息
   */
  getSyntaxErrorMessage(originalMessage) {
    const messageMap = {
      'Unexpected token': '语法错误：意外的符号',
      'Expected': '语法错误：缺少必要的符号',
      'Unterminated string': '语法错误：字符串未正确结束',
      'Missing semicolon': '语法错误：缺少分号',
      'Invalid character': '语法错误：无效字符',
      'Unexpected end of input': '语法错误：代码未完整',
      '检测到中文标点符号': '语法错误：使用了中文标点符号',
      'pen命令后必须加分号': '语法错误：pen命令后必须加分号'
    }

    for (const [key, value] of Object.entries(messageMap)) {
      if (originalMessage.includes(key)) {
        return value
      }
    }

    return `语法错误：${originalMessage}`
  }

  /**
   * 获取运行时错误的用户友好消息
   * @param {string} originalMessage - 原始错误消息
   * @returns {string} 用户友好的错误消息
   */
  getRuntimeErrorMessage(originalMessage) {
    const messageMap = {
      'Cannot read property': '运行时错误：无法访问属性',
      'is not a function': '运行时错误：不是有效的函数',
      'Cannot access': '运行时错误：无法访问变量',
      'ReferenceError': '运行时错误：未定义的变量或函数',
      'TypeError': '运行时错误：类型错误',
      'RangeError': '运行时错误：数值超出范围'
    }

    for (const [key, value] of Object.entries(messageMap)) {
      if (originalMessage.includes(key)) {
        return value
      }
    }

    return `运行时错误：${originalMessage}`
  }

  /**
   * 获取语法错误建议
   * @param {string} errorMessage - 错误消息
   * @param {string} errorLine - 错误行代码
   * @returns {string} 修复建议
   */
  getSyntaxSuggestion(errorMessage, errorLine) {
    if (errorMessage.includes('检测到中文标点符号')) {
      return '请将中文标点符号替换为对应的英文标点符号'
    }
    if (errorMessage.includes('pen命令后必须加分号')) {
      return '请在pen命令后添加分号'
    }
    if (errorMessage.includes('Unexpected token')) {
      return '请检查括号、引号或分号是否匹配'
    }
    if (errorMessage.includes('Expected')) {
      return '请检查是否缺少必要的符号'
    }
    if (errorMessage.includes('Unterminated string')) {
      return '请检查字符串是否正确使用双引号包围'
    }
    if (errorLine.includes('pen.') && !errorLine.includes('(')) {
      return 'pen命令后需要添加括号和参数'
    }
    if (errorMessage.includes('pen命令后不能使用') && errorMessage.includes('作为连接符')) {
      return 'pen命令后只能使用点号(.)连接。'
    }
    if (errorMessage.includes('链式调用中不能使用') && errorMessage.includes('作为连接符')) {
      return '链式调用中只能使用点号(.)连接。'
    }
    if (errorMessage.includes('需要参数，但没有提供参数')) {
      return '该命令需要参数，请在括号内提供参数。'
    }
    if (errorMessage.includes('缺少括号')) {
      return 'pen命令后必须添加括号，即使没有参数也要使用空括号()。'
    }
    if (errorMessage.includes('必须使用点号(.)连接')) {
      return 'pen命令后必须使用点号(.)连接方法名。'
    }
    return '请检查代码语法是否正确'
  }

  /**
   * 获取运行时错误建议
   * @param {string} errorMessage - 错误消息
   * @returns {string} 修复建议
   */
  getRuntimeSuggestion(errorMessage) {
    if (errorMessage.includes('Cannot read property')) {
      return '请检查变量是否已正确定义'
    }
    if (errorMessage.includes('is not a function')) {
      return '请检查函数名是否正确'
    }
    if (errorMessage.includes('ReferenceError')) {
      return '请检查变量或函数是否已定义'
    }
    return '请检查代码逻辑是否正确'
  }

  /**
   * 验证代码是否有潜在问题
   * @param {string} code - 源代码
   * @returns {Array} 警告列表
   */
  validateCode(code) {
    const warnings = []
    const lines = code.split('\n')
    let hasMainFunction = false
    let braceCount = 0
    let parenCount = 0
    
    // 调试信息：记录代码行数
    logger.log(`🔍 代码验证开始，总行数: ${lines.length}`)

    lines.forEach((line, index) => {
      const trimmedLine = line.trim()
      
      // 检查是否有main函数
      if (trimmedLine.includes('int main()') || trimmedLine.includes('int main (')) {
        hasMainFunction = true
      }

      // 检查无限循环
      if (trimmedLine.includes('for(') && !trimmedLine.includes('i++') && !trimmedLine.includes('i--')) {
        warnings.push({
          type: 'warning',
          message: '检测到可能的无限循环',
          line: index + 1,
          code: trimmedLine,
          suggestion: '请确保循环有正确的终止条件'
        })
      }

      // 检查未闭合的括号
      const openParens = (trimmedLine.match(/\(/g) || []).length
      const closeParens = (trimmedLine.match(/\)/g) || []).length
      parenCount += openParens - closeParens
      if (parenCount < 0) {
        warnings.push({
          type: 'error',
          message: '检测到多余的右括号',
          line: index + 1,
          code: trimmedLine,
          suggestion: '请检查括号是否匹配'
        })
      }

      // 检查未闭合的大括号
      const openBraces = (trimmedLine.match(/\{/g) || []).length
      const closeBraces = (trimmedLine.match(/\}/g) || []).length
      braceCount += openBraces - closeBraces
      if (braceCount < 0) {
        warnings.push({
          type: 'error',
          message: '检测到多余的大括号',
          line: index + 1,
          code: trimmedLine,
          suggestion: '请检查大括号是否匹配'
        })
      }

      // 检查未闭合的引号
      const quotes = (trimmedLine.match(/"/g) || []).length
      if (quotes % 2 !== 0) {
        warnings.push({
          type: 'error',
          message: '检测到未闭合的引号',
          line: index + 1,
          code: trimmedLine,
          suggestion: '请检查字符串是否正确使用双引号包围'
        })
      }

      // 检查缺少分号
      // 处理行内注释：如果包含//，检查分号是否在注释之前
      let lineToCheck = trimmedLine;
      if (trimmedLine.includes('//')) {
        const commentIndex = trimmedLine.indexOf('//');
        lineToCheck = trimmedLine.substring(0, commentIndex).trim();
      }
      
      // 检查lineToCheck是否以}结尾（处理 } //注释 的情况）
      const endsWithBrace = lineToCheck.endsWith('}') || trimmedLine.endsWith('}');
      
      if (lineToCheck && !lineToCheck.endsWith(';') && !trimmedLine.endsWith('{') && 
          !endsWithBrace && !trimmedLine.startsWith('//') && 
          !trimmedLine.startsWith('/*') && !trimmedLine.includes('int main') &&
          !trimmedLine.includes('for(') && !trimmedLine.includes('if(') &&
          !trimmedLine.includes('return')) {
        
        // 特殊处理：pen命令必须加分号
        if (lineToCheck.includes('pen.')) {
          warnings.push({
            type: 'error',
            message: 'pen命令后必须加分号',
            line: index + 1,
            code: trimmedLine,
            suggestion: '请在pen命令后添加分号'
          })
        } else {
          warnings.push({
            type: 'error',
            message: '可能缺少分号',
            line: index + 1,
            code: trimmedLine,
            suggestion: '请检查语句末尾是否添加了分号'
          })
        }
      }

      // 检查拼写错误（支持pen.和p.两种形式）
      if (trimmedLine.includes('pen.') || trimmedLine.includes('p.')) {
        // 有效的TOC命令列表（全部转为小写用于比较，支持 moveTo/lineTo/picL 的驼峰式）
        const validCommands = ['fd', 'bk', 'rt', 'lt', 'up', 'down', 'size', 'c', 'o', 'oo', 'e', 'ee', 'r', 'rr', 'text', 'show', 'hide', 'cls', 'speed', 'moveto', 'lineto', 'pic', 'picl', 'textsize', 'setprecision', 'textu', 'picu', 'font'];
        // 创建大小写不敏感的映射
        const validCommandsMap = new Map();
        validCommands.forEach(cmd => {
          validCommandsMap.set(cmd.toLowerCase(), true);
        });
        
        // 合法的驼峰式命令（这些命令可以有大小写混合）
        const camelCaseCommands = new Set(['moveto', 'lineto', 'picl', 'textsize', 'setprecision', 'textu', 'picu', 'font']);
        
        // 检查是否有拼写错误的命令名（如dk应该是bk）
        const commonMisspellings = {
          'dk': 'bk',
          'forward': 'fd',
          'back': 'bk',
          'right': 'rt',
          'left': 'lt',
          'upward': 'up',
          'downward': 'down',
          'color': 'c',
          'circle': 'o',
          'rect': 'r',
          'rectangle': 'r',
          'clear': 'cls',
          'move': 'moveTo',
          'line': 'lineTo',
          'picture': 'pic'
        };
        
        let hasSpellingError = false;
        let hasInvalidCommand = false;
        let hasUppercaseCommand = false;
        let suggestedCommand = '';
        let wrongCommand = '';
        
        // 检查所有命令（包括第一个命令和链式调用中的命令）
        const allCommandMatches = trimmedLine.match(/(?:pen|p)\.(\w+)\(|\.(\w+)\(/g);
        if (allCommandMatches) {
          for (const match of allCommandMatches) {
            // 提取命令名（去掉 . 和 (）
            const command = match.replace(/^(?:pen|p)\.|^\./, '').replace(/\($/, '');
            const commandLower = command.toLowerCase();
            
            // 检查是否是无效命令（大小写不敏感，支持 moveTo/lineTo 的驼峰式）
            if (!validCommandsMap.has(commandLower)) {
              hasInvalidCommand = true;
              wrongCommand = command;
              break;
            }
            
            // 检查是否有非法的大写字母（排除合法的驼峰式命令 moveTo, lineTo, picL）
            if (!camelCaseCommands.has(commandLower) && command !== commandLower) {
              hasUppercaseCommand = true;
              wrongCommand = command;
              break;
            }
            
            // 检查是否是拼写错误（排除自己映射到自己的情况）
            if (commonMisspellings[command] && commonMisspellings[command] !== command) {
              hasSpellingError = true;
              suggestedCommand = commonMisspellings[command];
              wrongCommand = command;
              break;
            }
          }
        }
        
        // 只有发现错误时才报错
        if (hasInvalidCommand || hasSpellingError || hasUppercaseCommand) {
          let suggestion = '请检查pen命令是否正确拼写，命令名应为小写';
          if (hasInvalidCommand) {
            suggestion = `'${wrongCommand}' 不是有效的TOC命令，请检查命令名是否正确`;
          } else if (hasSpellingError) {
            suggestion = `检测到拼写错误，建议使用 '${suggestedCommand}' 而不是 '${wrongCommand}'`;
          } else if (hasUppercaseCommand) {
            suggestion = '请检查pen命令是否正确拼写，命令名应为小写';
          }
          
          warnings.push({
            type: 'error',
            message: '检测到可能的命令拼写错误',
            line: index + 1,
            code: trimmedLine,
            suggestion: suggestion
          })
        }
      }

      // 检查中文标点符号（只检测命令部分，不检测字符串内容和注释）
      if (!trimmedLine.startsWith('//')) {
        // 移除字符串内容，只检查命令部分
        let commandPart = trimmedLine
        // 移除双引号字符串内容（正确处理转义字符）
        commandPart = commandPart.replace(/"(?:[^"\\]|\\.)*"/g, '""')
        // 移除单引号字符串内容（正确处理转义字符）
        commandPart = commandPart.replace(/'(?:[^'\\]|\\.)*'/g, "''")
        // 移除行内注释（// 后面的内容）
        commandPart = commandPart.replace(/\/\/.*$/, '')
        
        // 中文标点符号映射表
        const chinesePunctuationMap = {
          '；': ';',  '，': ',',  '（': '(',  '）': ')',  '【': '[',  '】': ']',
          '｛': '{',  '｝': '}',  '《': '<',  '》': '>',  '：': ':',  '！': '!',
          '？': '?',  '＂': '"',  '＇': "'",  '＼': '\\', '｜': '|',  '＆': '&',
          '＠': '@',  '＃': '#',  '＄': '$',  '％': '%',  '＾': '^',  '～': '~',
          '｀': '`',  '－': '-',  '＝': '=',  '＋': '+',  '＊': '*',  '／': '/',
          '＜': '<',  '＞': '>',  '［': '[',  '］': ']'
        };
        
        // 检查命令部分是否包含中文标点符号
        for (const [chinesePunct, englishPunct] of Object.entries(chinesePunctuationMap)) {
          if (commandPart.includes(chinesePunct)) {
            warnings.push({
              type: 'error',
              message: `检测到中文标点符号 "${chinesePunct}"`,
              line: index + 1,
              code: trimmedLine,
              suggestion: `请将 "${chinesePunct}" 替换为英文标点符号 "${englishPunct}"`
            })
            break; // 只报告第一个发现的中文标点符号
          }
        }
        
        // 检查命令部分是否包含中文字符（除了标点符号）
        if (/[\u4e00-\u9fff]/.test(commandPart)) {
          warnings.push({
            type: 'error',
            message: '检测到中文字符',
            line: index + 1,
            code: trimmedLine,
            suggestion: '请使用英文输入法编写代码'
          })
        }
      }
    })

    // 检查是否有main函数
    if (!hasMainFunction) {
      warnings.push({
        type: 'error',
        message: '缺少int main()函数',
        line: 1,
        code: '',
        suggestion: '请添加int main()函数作为程序入口'
      })
    }

    // 检查括号是否匹配
    if (parenCount > 0) {
      warnings.push({
        type: 'error',
        message: '检测到未闭合的括号',
        line: lines.length,
        code: '',
        suggestion: '请检查所有括号是否匹配'
      })
    }

    if (braceCount > 0) {
      warnings.push({
        type: 'error',
        message: `检测到未闭合的大括号（缺少 ${braceCount} 个右大括号）`,
        line: lines.length,
        code: '',
        suggestion: '请检查所有大括号是否匹配，确保每个 { 都有对应的 }'
      })
    }

    // 调试信息：记录最终结果
    logger.log(`🔍 代码验证完成，警告数量: ${warnings.length}`)
    if (warnings.length > 0) {
      logger.log('⚠️ 警告详情:', warnings)
    }

    return warnings
  }
}

// 导出错误处理器
export default GocErrorHandler
